<?php
namespace Core;

use DI\ContainerBuilder;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;

class BeanFactory
{
    private static $env = []; //env 配置文件
    private static $cotainer; //ioc 容器
    private static $handlers = [];
    public static function init() //初始化函数

    {
        self::$env = parse_ini_file(ROOT_PAHT . "/env");

        $builder = new ContainerBuilder(); //初始化容器Builder
        $builder->useAnnotations(true); //启用注解，主要是用它的Inject注解
        self::$cotainer = $builder->build(); //容器初始化

        $handlers = glob(ROOT_PAHT . "/core/annotationhandlers/*.php");
        foreach($handlers as $handler){
            self::$handlers = array_merge(self::$handlers,require_once($handler));
        }

        self::$handlers = require_once ROOT_PAHT . "/core/annotations/AnnotationHandlers.php";
        self::ScanBeans(); //扫描
    }

    private static function getEnv(string $key, string $default = "")
    { //获取env文件中的配置内容
        if (isset(self::$env[$key])) {
            return self::$env[$key];
        }

        return $default;
    }
    public static function getBean($name)
    {
        return self::$cotainer->get($name);
    }
    public static function ScanBeans()
    {
        //读取注解 对应的handler

        $scan_dir = self::getEnv("scan_dir", ROOT_PAHT . "/app"); //扫描路径
        $scan_root_namespace = self::getEnv("scan_root_namespace", "App\\"); //扫描的 namespace
        $files = glob($scan_dir . "/*.php");
        foreach ($files as $file) {
            require_once $file;
        }
        $reader = new AnnotationReader();
        // AnnotationRegistry::registerAutoloadNamespace("Core\annotations");
        AnnotationRegistry::registerLoader('class_exists');

        foreach (get_declared_classes() as $class) {
            if (strstr($class, $scan_root_namespace)) {
                $ref_class = new \ReflectionClass($class); //目标类的反射对象
                $class_annos = $reader->getClassAnnotations($ref_class); //获取所有类注解

                /////下方是处理 类注解
                foreach ($class_annos as $class_anno) {
                    $handler = self::$handlers[get_class($class_anno)]; //获取handler处理过程
                    $instance = self::$cotainer->get($ref_class->getName());
                    //处理属性注解
                    self::handlerPropAnno($instance, $ref_class, $reader);
                    //处理方法注解
                    self::handlerMethodAnno($instance,$ref_class,$reader);
                    ///
                    $handler($instance, self::$cotainer, $class_anno); //执行类注解处理

                }
            }
        }
    }
    /**
     * 处理属性注解
     *
     * @param [type] $instance
     * @param \ReflectionProperty $ref_property
     * @param AnnotationReader $reader
     * @return void
     */
    private static function handlerPropAnno(&$instance, \ReflectionProperty $ref_class, AnnotationReader $reader)
    {
        // var_dump($ref_class);exit;
        /*
            object(ReflectionClass)#18 (1) {
                ["name"]=>
                    string(30) "App\controllers\UserController"
            }
        */
        $props = $ref_class->getProperties(); //取出反射对象所有属性
        // var_dump($props);exit;
        /*
        array(1) {
        [0]=>
        object(ReflectionProperty)#28 (2) {
        ["name"]=>
        string(7) "version"
        ["class"]=>
        string(30) "App\controllers\UserController"
        }
        }
         */
        foreach ($props as $prop) {
            // var_dump($prop);exit;
            /*
                object(ReflectionProperty)#28 (2) {
                    ["name"]=>
                        string(7) "version"
                    ["class"]=>
                        string(30) "App\controllers\UserController"
                }
            */
            $prop_annos = $reader->getPropertyAnnotations($prop);
            // var_dump($prop_annos);exit;
            /*
            array(1) {
                [0]=>
                    object(Core\annotations\Value)#33 (1) {
                        ["name"]=>
                            string(7) "version"
                    }
            }
             */
            foreach ($prop_annos as $prop_anno) {
                // var_dump(self::$handlers);exit;
                /*
                array(2) {
                ["Core\annotations\Bean"]=>
                    object(Closure)#10 (1) {
                        ["parameter"]=>
                            array(3) {
                        ["$instance"]=>
                            string(10) "<required>"
                        ["$container"]=>
                            string(10) "<required>"
                        ["$self"]=>
                            string(10) "<required>"
                        }
                    }
                ["Core\annotations\Value"]=>
                    object(Closure)#11 (1) {
                        ["parameter"]=>
                            array(3) {
                               ["$prop"]=>
                                    string(10) "<required>"
                               ["$instance"]=>
                                    string(10) "<required>"
                               ["$self"]=>
                                    string(10) "<required>"
                            }
                        }
                    }
                 */
                $handler = self::$handlers[get_class($prop_anno)];
                $instance = $handler($prop, $instance, $prop_anno); //处理属性注解
            }
        }

    }
    /**
     * 处理方法注解
     *
     * @param [type] $instance
     * @param \ReflectionClass $ref_class
     * @param AnnotationReader $reader
     * @return void
     */
    private static function handlerMethodAnno(&$instance, \ReflectionClass $ref_class, AnnotationReader $reader){
        $methods = $ref_class->getMethods();//取出反射对象所有方法
        foreach($methods as $method){
            $method_annos = $reader->getMethodAnnotations($method);
            foreach($method_annos as $method_anno){
                $handler = self::$handlers[get_class($method_anno)];
                $instance = $handler($method,$instance,$method_anno);//处理方法注解
            }
        }
    }

}
